use crate::{
    models::entity::{
        perm,
        prelude::{Perm, RolePerm},
    },
    utils::{redis_key::RedisKey, redis_util::RedisUtil},
};
use actix_web::{dev::Payload, web::Data, Error, FromRequest, HttpMessage, HttpRequest};
use futures::future::{err, ok, Ready};
use log::info;
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
use serde::{Deserialize, Serialize};

use crate::common::error::ApiError;

use super::state::AppState;

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct AuthInfo {
    pub user_id: i32,
    pub role_ids: Vec<i32>,
}

pub struct AuthPath;

impl AuthPath {
    pub async fn init(state: &Data<AppState>) -> Result<(), ApiError> {
        info!("Initializing Role Perm...");

        let perm = Perm::find()
            .filter(perm::Column::Type.eq(1))
            .all(&state.db)
            .await
            .expect("Failed to initialize Perm");

        let role_perm = RolePerm::find()
            .all(&state.db)
            .await
            .expect("Failed to initialize RolePerm");

        for p in perm {
            let mut role_ids = role_perm
                .iter()
                .filter(|r| r.perm_id == p.id)
                .map(|r| r.role_id)
                .collect::<Vec<i32>>();
            role_ids.push(1);

            let role_ids_json = serde_json::to_string(&role_ids)?;

            RedisUtil::hset(&state.redis, RedisKey::PATH, &p.path, &role_ids_json)?;
        }

        Ok(())
    }
}

impl FromRequest for AuthInfo {
    type Error = Error;
    type Future = Ready<Result<Self, Self::Error>>;

    fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future {
        if let Some(auth_info) = req.extensions().get::<AuthInfo>() {
            ok(auth_info.clone())
        } else {
            err(ApiError::Forbidden("无权限1").into())
        }
    }
}
